package main

import (
	"fmt"
	"math/rand"
)

// 享元对象：树的类型（内部状态）
type TreeType struct {
	name    string // 树种名称（共享数据）
	texture string // 3D模型路径（共享数据）
}

func (t *TreeType) Display(x, y int, age float64) {
	fmt.Printf("渲染 %s 树 [坐标(%d,%d) 树龄%.1f年] 使用模型: %s\n",
		t.name, x, y, age, t.texture)
}

// ---------------------- 享元工厂 ----------------------
type TreeFactory struct {
	treeTypes map[string]*TreeType // 类型缓存池
}

func NewTreeFactory() *TreeFactory {
	return &TreeFactory{
		treeTypes: make(map[string]*TreeType),
	}
}

// 获取享元对象（核心方法）
func (f *TreeFactory) GetTreeType(name string) *TreeType {
	if t, exists := f.treeTypes[name]; exists {
		return t // 返回缓存对象
	}

	// 模拟加载资源文件（耗时操作）
	newType := &TreeType{
		name:    name,
		texture: fmt.Sprintf("/models/trees/%s.obj", name),
	}
	f.treeTypes[name] = newType
	return newType
}

// ---------------------- 外部状态容器 ----------------------
type Tree struct {
	treeType *TreeType // 共享的内部状态
	x, y     int       // 外部状态：坐标
	age      float64   // 外部状态：树龄
}

func NewTree(factory *TreeFactory, name string, x, y int) *Tree {
	return &Tree{
		treeType: factory.GetTreeType(name),
		x:        x,
		y:        y,
		age:      0,
	}
}

func (t *Tree) Grow(years float64) {
	t.age += years
}

func (t *Tree) Display() {
	t.treeType.Display(t.x, t.y, t.age)
}

// ---------------------- 森林系统 ----------------------
type Forest struct {
	trees []*Tree
}

func (f *Forest) PlantTree(factory *TreeFactory, name string, x, y int) {
	tree := NewTree(factory, name, x, y)
	f.trees = append(f.trees, tree)
}

func (f *Forest) DisplayAll() {
	for _, tree := range f.trees {
		tree.Display()
	}
}

// ---------------------- 客户端调用 ----------------------
func main() {
	factory := NewTreeFactory()
	forest := &Forest{}

	// 种植100万棵松树（共享同个TreeType）
	for i := 0; i < 1000; i++ {
		forest.PlantTree(factory, "pine", rand.Intn(1000), rand.Intn(1000))
	}

	// 种植50万棵橡树（共享另一个TreeType）
	for i := 0; i < 500; i++ {
		forest.PlantTree(factory, "oak", rand.Intn(1000), rand.Intn(1000))
	}

	// 内存对比：未用享元模式 → 150万TreeType对象；使用后 → 2个TreeType对象
	fmt.Printf("共缓存树种类型: %d\n", len(factory.treeTypes))

	// 显示部分树木状态
	forest.trees[0].Grow(5.2)
	forest.trees[0].Display()
	forest.trees[1000].Display()
}
